<?php
/**
 * OfferSpider.php class file.
 * @author wudg <544038230@qq.com>
 * @date 2020/10/26- 2:03 下午
 */

namespace common\drivers\spiderProduct;

use common\exception\DriverException;
use QL\QueryList;
use common\constants\PlatformConst;
use common\drivers\interfaces\SpiderProductInterface;

/**
 * 1688采集驱动
 * Class OfferSpider
 * @package common\drivers\spiderProduct
 */
class OfferSpider extends BaseSpider implements SpiderProductInterface
{

    //商品视频地址
    protected $videoUrl = "https://apps.1688.com/event/app/videoInfo/getVideoById.htm";

    //商品详情地址
    protected $productUrl;

    /**
     * @inheritDoc
     */
    public function getContents(string $url): string
    {
        $this->productUrl = $url;
        $response = $this->spiderContent($url);
        $html = $response->getBody()->getContents();
//        print_r($this->Utf8String($html));exit;
        //$html = file_get_contents("./1688.txt");
//dsfafdsaf

        $this->resources = $html ? $this->Utf8String($html) : '';
        return $this->resources;
    }

    /**
     * @inheritDoc
     */
    public function formatContents($params = []): array
    {
        if (!$this->resources) {
            throw new DriverException("商品获取失败");
        }
        $filter = QueryList::html($this->resources);
        $err = $filter->find("#err .tips")->text();
        if ($err) {
            throw new DriverException($err);
        }

        $this->productInfo['title'] = $filter->find("#mod-detail-title .d-title")->text();
        $this->productInfo['num_iid'] = $this->getData('offerid');//商品主键
        $this->productInfo['mall_id'] = $filter->find(".pagecollect")->attr("data-companyid"); //所属店铺id
        $this->productInfo['skus'] = $this->getSkus(); //sku属性信息

        $require_columns = ['title', 'skus', 'num_iid', 'mall_id'];
        foreach ($require_columns as $column) {
            if (!$this->productInfo[$column]) {
                throw new DriverException("商品采集失败");
            }
        }


        //$pics = $filter->find(".mod-detail-gallery ul img")->attrs("src")->all();

        $filter->find('.mod-detail-gallery ul li')->map(function ($row) {
            $img_config = $row->attr("data-imgs");
            $img_arr = $img_config ? json_decode($img_config, true) : [];
            if (isset($img_arr['original']) && $img_arr['original']) {
                $pic = str_replace("60x60", '', $img_arr['original']);
                $this->productInfo['pics'][] = $pic;
            }
        });

        if (count($this->productInfo['pics'])) {
            $this->productInfo['main_pic'] = $this->productInfo['pics'][0] . '_250x250.' . pathinfo($this->productInfo['pics'][0])['extension'];
        }

        $this->productInfo['platform'] = PlatformConst::PLATFORM_1688; //平台
        $this->productInfo['cid'] = $this->getData('catid');//商品类目id
        $this->productInfo['attr'] = $this->getAttrs($filter); //属性信息
        $this->productInfo['pc_desc'] = $this->getDesc($filter);//电脑端详细
        $this->productInfo['mall_name'] = $filter->find(".shop-info .company-name")->text();
        $this->productInfo['video'] = $this->getVideo($filter, $params);

        return $this->productInfo;
    }

    /**
     * 视频获取
     * @param $filter
     * @return string
     */
    protected function getVideo($filter)
    {
        $video_url = '';
        $config = $filter->find(".mod-detail-gallery")->attr("data-mod-config");
        $arr = $config ? json_decode($config, true) : [];
        $videoId = $arr['videoId'] ?? '';
        $memberId = $filter->find("#complaintOb")->attr("value");
        if (!$videoId || !$memberId) {
            return $video_url;
        }
        $product_id = $this->productInfo['num_iid'];
        $_params = ['site_id' => 'winport', 'videoId' => $arr['videoId'], 'memberId' => $memberId];
        $response = $this->spiderContentCurl($this->videoUrl, $_params, ['referer' => $this->productUrl]);
        if ($response) {
            $videoData = json_decode($response, true);
            $video_url = $videoData['result']['address'] ?? '';
        }
        return $video_url;
    }

    /**
     * 商品图文详情
     * @param $filter
     * @return mixed|string
     */
    protected function getDesc($filter)
    {
        $desc_url = $filter->find("#desc-lazyload-container")->attr("data-tfs-url");
        $desc_content = $desc_url ? file_get_contents($desc_url) : '';
        $content = '';
        if ($desc_content) {
            preg_match("/offer_details=(.*\s*?);/", $desc_content, $match);
            $_content = isset($match[1]) ? trim($match[1]) : '';
            $_content = $this->Utf8String($_content);
            $content_arr = $_content ? json_decode(trim($_content), true) : [];
            $content = $content_arr['content'] ?? '';
            if ($content) {
                preg_match_all("/\<[img|IMG].*?src=['|\"](.*?(?:[.gif|.jpg]))['|\"].*?[\/]?>/", $content, $matchImg);
                if (count($matchImg)) {
                    $m_desc = [];
                    foreach($matchImg as $_matchImg) {
                        if(is_array($_matchImg)) {
                            $m_desc[] = implode("",$_matchImg);
                        }else{
                            $m_desc[] = $_matchImg;
                        }
                    }
                    $this->productInfo['m_desc'] = implode('', $m_desc);
                }
            }

        }
        if (!$content) {
            $this->errorInfo['content'] = '商品详情获取失败';
        }
        return $content;
    }

    /**
     * js key-value值获取
     * @param $name
     * @return int
     */
    protected function getData($name)
    {
        preg_match("/$name:(.*\s*?),/", $this->resources, $match);
        //print_R($match);exit;
        $cid = isset($match[1]) ? str_replace("'", '', $match[1]) : 0;
        return trim($cid);
    }

    /**
     * @param $match
     * @param int $substr_len
     * @return array|mixed
     */
    protected function jsonToArr($match, $substr_len = 0)
    {
        $json = isset($match[1]) ? trim($match[1]) : '';
        $substr_len && $json = substr($json, 0, $substr_len);
        $arr = $json ? json_decode($json, true) : [];
        return $arr;
    }

    /**
     * 数组排列组合
     * @param array $options
     * @return array
     */
    protected function combination(array $options)
    {
        $rows = [];

        foreach ($options as $option => $items) {
            if (count($rows) > 0) {
                // 2、将第一列作为模板
                $clone = $rows;

                // 3、置空当前列表，因为只有第一列的数据，组合是不完整的
                $rows = [];

                // 4、遍历当前列，追加到模板中，使模板中的组合变得完整
                foreach ($items as $item) {
                    $tmp = $clone;
                    foreach ($tmp as $index => $value) {
                        $value[$option] = $item;
                        $tmp[$index] = $value;
                    }

                    // 5、将完整的组合拼回原列表中
                    $rows = array_merge($rows, $tmp);
                }
            } else {
                // 1、先计算出第一列
                foreach ($items as $item) {
                    $rows[][$option] = $item;
                }
            }
        }

        return $rows;
    }

    /**
     * priceRange 格式下 生成sku 属性
     * @return array
     */
    protected function formatSkuProperties()
    {
        preg_match("/skuProps:(.*\s*?),/", $this->resources, $match);
        $props = $this->jsonToArr($match);
        $list = [];
        $increament = 1000;
        $newProps = [];
        foreach ($props as $k => &$prop) {
            $prop_id = $increament + $k;
            $list[$k] = [];
            foreach ($prop['value'] as $index => &$value) {
                $valueId = $prop_id * 1000 + $index;
                $newProps[$valueId] = ['prop_name' => $prop['prop'], 'prop_id' => $prop_id, 'name' => $value['name'], 'sku_img' => $value['imageUrl'] ?? ''];
                $list[$k][] = $valueId;
            }
        }
        $return = [];
        $combination = $this->combination($list);
        foreach ($combination as $combin) {
            $name_arr = [];
            $properties = [];
            $properties_name = [];
            $sku_img = '';
            foreach ($combin as $key) {
                $name = $newProps[$key]['name'] ?? '';
                $name_arr[] = $name;
                $prop_id = $newProps[$key]['prop_id'] ?? '';
                $prop_name = $newProps[$key]['prop_name'] ?? '';
                $properties[] = $prop_id . ":" . $key;
                $properties_name[] = $prop_name . ":" . $name;
                if (isset($newProps[$key]['sku_img']) && $newProps[$key]['sku_img']) {
                    $sku_img = [
                        'name' => $prop_name,
                        'value' => $name,
                        'skuImg' => $newProps[$key]['sku_img'],
                        'key' => $prop_id . ":" . $key,
                    ];
                }
            }
            $key_name = implode("&gt;", $name_arr);
            $return[$key_name] = [
                'properties' => $properties,
                'properties_name' => $properties_name,
                'skuImg' => $sku_img
            ];
        }
        return $return;
    }

    /**
     * JS sku数据获取
     * @param $filter
     */
    protected function getSkus()
    {

        $skus = [];
        $priceRangeProperties = [];//priceRange格式下获取该值

        /**
         * 获取priceRange格式下的商品价格
         */
        preg_match("/priceRange:(.*\s*?),/", $this->resources, $matchPrice);
        $price_arr = $this->jsonToArr($matchPrice);
        $index = count($price_arr) - 1;
        $default_price = $price_arr[$index][1] ?? 0;

        preg_match("/skuMap:(.*\s*?)end/", $this->resources, $match);
        $arr = $this->jsonToArr($match, '-1');
        if (!$arr) {
            throw new DriverException("商品SKU获取失败");
        }
        $price = 0;
        $skuImgs = [];
        foreach ($arr as $spec => $sku) {
            $properties = [];
            $properties_name = [];
            if (!isset($sku['specAttrs'])) {
                $priceRangeProperties = $priceRangeProperties ? $priceRangeProperties : $this->formatSkuProperties();
                if (isset($priceRangeProperties[$spec]['skuImg']) && $priceRangeProperties[$spec]['skuImg']) {
                    $skuImgs[$priceRangeProperties[$spec]['skuImg']['key']] = $priceRangeProperties[$spec]['skuImg'];
                }
                $properties = $priceRangeProperties[$spec]['properties'] ?? '';
                $properties_name = $priceRangeProperties[$spec]['properties_name'] ?? '';
            } else {
                $specArr = $sku['specAttrs'] ?? [];
                foreach ($specArr as $_spec) {
                    $fid = $_spec['fid'] ?? '';
                    $valueId = $_spec['valueId'];
                    $name = $_spec['name'] ?? '';
                    $value = $_spec['value'] ?? '';
                    if ($fid && $valueId && $name && $value) {
                        $properties[] = $fid . ":" . $valueId;
                        $properties_name[] = $name . ":" . $value;
                    }
                }
            }

            $_price = $sku['discountPrice'] ?? '';
            if (!$_price) {
                $_price = $default_price;
            }
            if ($price > $_price) {
                $price = $_price;
            }
            $skus[] = [
                'skuId' => $sku['skuId'] ?? '',
                'stock' => $sku['canBookCount'] ?? 0,
                'price' => $_price,
                'properties' => $properties ? json_encode($properties, JSON_UNESCAPED_UNICODE) : '',
                'properties_name' => $properties_name ? json_encode($properties_name, JSON_UNESCAPED_UNICODE) : '',
            ];
        }
        $this->productInfo['sku_img'] = $skuImgs ? array_values($skuImgs) : '';
        $this->productInfo['prices'] = $price;
        return $skus;
    }

    /**
     * 商品属性
     * @param $filter
     */
    protected function getAttrs($filter)
    {
        $descTable = $filter->find("#mod-detail-attributes table");
        $descRows = $descTable->find('tr')->map(function ($row) {
            return $row->find('td')->texts()->all();
        });
        $attrs = [];
        foreach ($descRows->all() as $desc) {
            $_desc = array_chunk($desc, 2);
            foreach ($_desc as $attr) {
                if (isset($attr[0]) && isset($attr[1])) {
                    $attrs[] = ['key' => $attr[0], 'value' => $attr[1]];
                }
            }
        }
        if (!$attrs) {
            $this->errorInfo['attr'] = '商品属性获取失败';
        }
        return $attrs;
    }

    /**
     * @inheritDoc
     */
    public function setErrorInfo(string $msg = '')
    {
        // TODO: Implement setErrorInfo() method.
    }

    /**
     * @inheritDoc
     */
    public function saveDb()
    {
        echo '1688-入库' . PHP_EOL;
        // TODO: Implement saveDb() method.
    }

    /**
     * @inheritDoc
     */
    public function getErrorInfo()
    {
        return $this->errorInfo;
    }
}